package com.ruoyi.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.domain.entity.SysArea;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.AreaUtils;
import com.ruoyi.system.mapper.SysAreaMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.ISysAreaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 地区Service业务层处理
 *
 * @author shuyan
 * @date 2020-11-05
 */
@Service
@CacheConfig(cacheNames = "area")
public class SysAreaServiceImpl implements ISysAreaService {
    @Autowired
    private SysAreaMapper sysAreaMapper;
    @Autowired
    private SysUserMapper userMapper;

    /**
     * 获取全国区划
     */
    public SysArea getCountryArea() {
        SysArea area = new SysArea();
        area.setId(0L);
        area.setCode("");
        area.setStandardCode("");
        area.setName("全国");
        area.setLevel(0);
        return area;
    }


    @Override
    @Cacheable(key = "T(String).valueOf('children:').concat(#useLocale).concat('_').concat(#parentCode)")
    public List<SysArea> listByParent(Boolean useLocale, String parentCode) {
        SysArea sysArea = new SysArea();
        sysArea.setParentCode(parentCode);
        sysArea.setUseLocale(useLocale);
        List<SysArea> areaList = sysAreaMapper.listAreasExactly(sysArea);
        for (SysArea area : areaList) {
            String code = area.getCode();
            int childCount = sysAreaMapper.childCount(AreaUtils.getAreaTable(useLocale), code);
            area.setChildCount(childCount);
            area.setParent(childCount > 0);
        }
        return areaList;
    }

    @Override

    public List<SysArea> listByParentUser(Boolean useLocale, String parentCode) {
        SysArea sysArea = new SysArea();
        sysArea.setParentCode(parentCode);
        sysArea.setUseLocale(useLocale);
        List<SysArea> areas = sysAreaMapper.listAreasExactly(sysArea);
        SysUser sysUser = new SysUser();
        sysUser.setAreaCode(parentCode);
        List<SysUser> list = userMapper.selectAreaUserList(sysUser);
        for (int i = 0; i < list.size(); i++) {
            SysArea area = new SysArea();
            SysUser user = list.get(i);
            area.setParentCode(parentCode);
            area.setUseLocale(useLocale);
            area.setLevel(6);
            area.setCode(user.getUserName());
            area.setId(user.getUserId());
            area.setName(user.getNickName());
            areas.add(area);

        }
        return areas;
    }

    @Override
    @Cacheable(key = "T(String).valueOf('code:').concat(#useLocale).concat('_').concat(#code)")
    public SysArea getByCode(Boolean useLocale, String code) {
        if (Objects.equals("", code)) {
            return getCountryArea();
        }
        SysArea sysArea = new SysArea();
        sysArea.setUseLocale(useLocale);
        sysArea.setCode(code);
        List<SysArea> areas = sysAreaMapper.listAreasExactly(sysArea);
        if (areas.size() > 0) {
            SysArea area = areas.get(0);
            area.setUseLocale(useLocale);
            return area;
        }
        return null;
    }

    @Override
    @Cacheable(key = "T(String).valueOf('id:').concat(#useLocale).concat('_').concat(#id)")
    public SysArea getById(Boolean useLocale, Long id) {
        if (id == 0) {
            return getCountryArea();
        }
        SysArea sysArea = new SysArea();
        sysArea.setUseLocale(useLocale);
        sysArea.setId(id);
        List<SysArea> areas = sysAreaMapper.listAreasExactly(sysArea);
        if (areas.size() > 0) {
            SysArea area = areas.get(0);
            area.setUseLocale(useLocale);
            return area;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = "area", allEntries = true)
    public int importAreas(List<Map<String, String>> mapList, Boolean useLocale, boolean cleanImport) {
        //首先清除地区
        String tableName = AreaUtils.getAreaTable(useLocale);
        if (cleanImport) {
            sysAreaMapper.cleanAreaTable(tableName);
        }
        //处理导入数据 分批导入
        int i = 0;
        if (mapList.size() > 0) {
            List<List<Map<String, String>>> split = CollUtil.split(mapList, 500);
            for (List<Map<String, String>> list : split) {
                i += sysAreaMapper.batchInsert(list, tableName);
            }
        }
        //导入数据后初始化其他字段
        sysAreaMapper.initAfterInsert(tableName);
        return i;
    }

    @Override
    @CacheEvict(cacheNames = "area", allEntries = true)
    public int syncFromStandard() {
        sysAreaMapper.cleanAreaTable(AreaUtils.getAreaTable(true));
        return sysAreaMapper.syncFromStandard();
    }

    /**
     * 修改地区  使用了以下参数: useLocale,id,name,code,parentCode;其中code为修改后的编码
     *
     * @param area 地区
     */
    @Override
    @CacheEvict(cacheNames = "area", allEntries = true)
    public int saveAreaWithCodes(SysArea area) {
        boolean useLocale = area.isUseLocale();
        String tableName = AreaUtils.getAreaTable(useLocale);
        Long areaId = area.getId();
        String areaCode = area.getCode();
        area.getParams().put("tableName", tableName);
        if (areaId == null) {
            //插入 设置各级别code
            Map<String, Object> eachLevelCodeMap = AreaUtils.getEachLevelCodeMap(areaCode);
            area.setLevel(MapUtil.getInt(eachLevelCodeMap, "level"));
            area.setParentCode(MapUtil.getStr(eachLevelCodeMap, "parentCode"));
            area.setCode1(MapUtil.getStr(eachLevelCodeMap, "code1"));
            area.setCode2(MapUtil.getStr(eachLevelCodeMap, "code2"));
            area.setCode3(MapUtil.getStr(eachLevelCodeMap, "code3"));
            area.setCode4(MapUtil.getStr(eachLevelCodeMap, "code4"));
            area.setCode5(MapUtil.getStr(eachLevelCodeMap, "code5"));
            //标准区划维护时设置标准地区码为本地地区码
            area.setStandardCode(useLocale ? null : areaCode);
            //保存地区
            return sysAreaMapper.insertArea(area);
        }
        //地区码未变化时只更新名称
        SysArea oldArea = getById(useLocale, areaId);
        if (Objects.equals(oldArea.getCode(), areaCode)) {
            return sysAreaMapper.updateAreaName(area);
        }
        //地区码变化,更新所有下级地区码
        area.getParams().put("oldCode", oldArea.getCode());
        //更新当前及所有关联地区码
        return sysAreaMapper.updateAreaWithAllChildren(area);
    }

    @Override
    @CacheEvict(cacheNames = "area", allEntries = true)
    public int removeAreas(Boolean useLocale, String code) {
        String tableName = AreaUtils.getAreaTable(useLocale);
        return sysAreaMapper.removeAreas(tableName, code);
    }

    @Override
    @CacheEvict(cacheNames = "area", allEntries = true)
    public int dropArea(List<SysArea> areas) {
        int rows = 0;
        for (SysArea area : areas) {
            rows += saveAreaWithCodes(area);
        }
        return rows;
    }

    @Override
    @Cacheable(key = "T(String).valueOf('eachlevel:').concat(#useLocale).concat('_').concat(#code)")
    public Map<Integer, SysArea> getEachLevelByCode(boolean useLocale, String code) {
        Map<String, Object> eachLevelCodeMap = AreaUtils.getEachLevelCodeMap(code);
        Map<Integer, SysArea> eachVo = new HashMap<>(5);
        for (int i = 1; i <= AreaUtils.MAX_LEVEL; i++) {
            String key = "code" + i;
            String curCode = MapUtil.getStr(eachLevelCodeMap, key);
            SysArea sysArea = null;
            if (StrUtil.isNotEmpty(curCode)) {
                sysArea = getByCode(useLocale, curCode);
            }
            eachVo.put(i, sysArea);
        }
        return eachVo;
    }

    @Override
    public List<SysArea> listByRootCodeAndLevel(boolean useLocale, String rootCode, Integer level) {
        String tableName = AreaUtils.getAreaTable(useLocale);
        return sysAreaMapper.listByRootCodeAndLevel(tableName, rootCode, level);
    }

    @Override
    @CacheEvict(cacheNames = "area", allEntries = true)
    public void cleanCaches() {
        //该方法用于清除所有缓存
    }
}
